package state


import ."api"


func (self *luaState) RawEqual(idx1, idx2 int) bool {

	if !self.stack.isValid(idx1) || !self.stack.isValid(idx2) {

		return false
	}

	a := self.stack.get(idx1)
	b := self.stack.get(idx2)

	return _eq(a, b, nil)
}


// 对指定索引处的两个值进行比较，返回结果
// 该方法不改变栈的状态
func (self *luaState) Compare(idx1, idx2 int, op CompareOp) bool {

	a := self.stack.get(idx1)
	b := self.stack.get(idx2)

	switch op {

		case LUA_OPEQ:		return _eq(a, b, self)

		case LUA_OPLT:		return _lt(a, b, self)

		case LUA_OPLE:		return _le(a, b, self)

		default:			panic("invalid compare op!")
	}

}


// 比较两个值是否相等
// 只有当两个操作数在Lua语言层面具有相同类型时
// 等于运算符才有可能返回true
// nil、布尔和字符串类型的等于操作比较简单
// 整数和浮点数仅仅在Lua实现层面有差别
// 在Lua语言层面统一表现为数字类型，因此需要相互转换
// 其它类型的值暂时先按引用进行比较
// 如果ls为nil值，表示不希望执行__eq元方法
func _eq(a, b luaValue, ls *luaState) bool {

	switch x := a.(type) {
		case nil:			return b == nil

		case bool:	
			y, ok := b.(bool)
			return ok && x == y

		case string:
			y, ok := b.(string)
			return ok && x == y

		case int64:
			switch y := b.(type) {
				case int64:		return x == y
				case float64:	return float64(x) == y
				default:		return false
			}
		case float64:
			switch y := b.(type) {
				case float64:	return x == y
				case int64:		return x == float64(y)
				default:		return x == y
			}
		case *luaTable:  // 元表
			if y, ok := b.(*luaTable); ok && x != y && ls != nil {  // x == y的话, 可以用a == b来比较 // TODO
				if result, ok := callMetamethod(x, y, "__eq", ls); ok {
					return convertToBoolean(result)
				}
			}
			return a == b

		default:			return a == b
	}
}


// 如果两个操作数都是数字，则进行数字比较
// 如果两个操作数都是字符串，则进行字符串比较
// 否则，尝试调用__lt元方法
func _lt(a, b luaValue, ls *luaState) bool {

	switch x := a.(type) {

		case string:
			if y, ok := b.(string); ok {
				return x < y
			}

		case int64:
			switch y := b.(type) {
				case int64:		return x < y
				case float64:	return float64(x) < y
			}

		case float64:
			switch y := b.(type) {
				case float64:	return x < y
				case int64:		return x < float64(y)
			}
	}

	if result, ok := callMetamethod(a, b, "__lt", ls); ok {
		return convertToBoolean(result)
	} else {
		panic("comparison error!")
	}

}


// 小于等于
// 如果Lua找不到__le元方法，则会尝试调用__lt元方法(假设a<=b等价于not (b<a))
func _le(a, b luaValue, ls *luaState) bool {

	switch x := a.(type) {

		case string:
			if y, ok := b.(string); ok {
				return x <= y
			}

		case int64:
			switch y := b.(type) {
				case int64:		return x <= y
				case float64:	return float64(x) <= y
			}

		case float64:
			switch y := b.(type) {
				case float64:	return x <= y
				case int64:		return x <= float64(y)
			}
	}

	if result, ok := callMetamethod(a, b, "__le", ls); ok {
		return convertToBoolean(result)
	} else if result, ok := callMetamethod(b, a, "__lt", ls); ok {
		return !convertToBoolean(result)
	} else {
		panic("comparison error!")
	}

}